package com.gitee.cashzhang27.test.cloud.oauth.auth.server.extended.filter;

import com.gitee.cashzhang27.test.cloud.oauth.auth.server.extended.entity.DictCodeEnums;
import com.gitee.cashzhang27.test.cloud.oauth.auth.server.extended.token.PhoneNumberVerifyCodeAuthenticationToken;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import lombok.Getter;
import lombok.Setter;
import lombok.SneakyThrows;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.authentication.AuthenticationEventPublisher;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

/**
 * @author Cash Zhang
 * @version v1.0
 * @since 2019/02/21 11:30
 */
public class PhoneNumberVerifyCodeAuthenticationFilter extends
    AbstractAuthenticationProcessingFilter {

  @Getter
  @Setter
  private AuthenticationEventPublisher eventPublisher;

  /**
   * 手机号
   */
  protected static final String SPRING_SECURITY_FORM_PHONE_NUMBER_KEY = "phoneNumber";
  /**
   * 验证码
   */
  protected static final String SPRING_SECURITY_FORM_VERIFY_CODE_KEY = "verifyCode";
  /**
   * 用户类型
   */
  protected static final String SPRING_SECURITY_FORM_USER_TYPE_KEY = "userType";

  @Getter
  @Setter
  private String phoneNumberParameter = SPRING_SECURITY_FORM_PHONE_NUMBER_KEY;

  @Getter
  @Setter
  private String verifyCodedParameter = SPRING_SECURITY_FORM_VERIFY_CODE_KEY;

  @Getter
  @Setter
  private String userTypeParameter = SPRING_SECURITY_FORM_USER_TYPE_KEY;

  @Getter
  @Setter
  private boolean postOnly = true;

  public PhoneNumberVerifyCodeAuthenticationFilter() {
    super(new AntPathRequestMatcher("/oauth/token/phone", "POST"));
  }

  @Override
  @SneakyThrows
  public Authentication attemptAuthentication(HttpServletRequest request,
      HttpServletResponse response) {

    if (postOnly && !HttpMethod.POST.matches(request.getMethod())) {
      throw new AuthenticationServiceException(
          "Authentication method not supported: " + request.getMethod());
    }

    String phoneNumber = obtainParameter(request, phoneNumberParameter);
    String verifyCode = obtainParameter(request, verifyCodedParameter);
    String userTypeStr = obtainParameter(request, userTypeParameter);
    DictCodeEnums userType = DictCodeEnums.valueOf(userTypeStr);

    phoneNumber = phoneNumber.trim();

    AbstractAuthenticationToken authRequest = new PhoneNumberVerifyCodeAuthenticationToken(
        phoneNumber, verifyCode,userType);

    // Allow subclasses to set the "details" property
    setDetails(request, authRequest);

    return this.getAuthenticationManager().authenticate(authRequest);
  }

  private String obtainParameter(HttpServletRequest request, String parameter) {
    String result = request.getParameter(parameter);
    return result == null ? "" : result;
  }

  private void setDetails(HttpServletRequest request,
      AbstractAuthenticationToken authRequest) {
    authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
  }
}

